package com.duanjc.mergemd.service;



import com.duanjc.mergemd.bean.DocumentContent;
import com.duanjc.mergemd.utils.FileCheckUtils;
import com.duanjc.mergemd.utils.FileIOUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;

/**
 * 本类用于合并 {@code MergeToMultipleFile} 与 {@code MergeToOneFile} 中重复的代码
 * <p>目录有两种意思：1.文件 2.文件中 h 标签组成的导航栏
 * <p>请注意区分，例：在文件中插入目录指的是在文件中插入导航栏
 *
 * @author cqh
 * @date 2022/03/13 17:15
 */
public abstract class AbstractMergeFile {
    /**
     * 文件后缀
     */
    protected String suffix;

    /**
     * 源目录
     */
    protected String srcPath;

    /**
     * 目标目录
     */
    protected String destPath;

    /**
     * 得到 src 路径下的所有子文件（包括更深层次），将其写入 dest 路径
     *
     * @param src  源目录
     * @param dest 指定要写入的目录
     * @throws IOException 找不到文件、读取异常、写入的文件是目录
     *                     、文件所在目录未创建都会抛出此异常
     */
    public void mergeFile(File src, File dest) throws IOException {
        if (src.isFile()) {
            String fileName = src.getName();
            if (FileCheckUtils.matches(fileName, suffix)) {

                BufferedReader bufferedReader = new BufferedReader(FileIOUtils.getReader(src));
                BufferedWriter bufferedWriter = new BufferedWriter(FileIOUtils.getWriter(dest, true));
                String line = null;

                try {
                    insertToDirectory(bufferedWriter, dest);
                    while ((line = bufferedReader.readLine()) != null) {
                        bufferedWriter.write(line);
                        bufferedWriter.newLine();
                    }
                    bufferedWriter.newLine();
                    bufferedWriter.flush();
                } finally {
                    bufferedReader.close();
                    bufferedWriter.close();
                }
            }
        } else if (src.isDirectory()) {
            for (File file : src.listFiles()) {
                mergeFile(file, dest);
            }
        }
    }

    /**
     * 此方法留给子类实现，决定插入目录的位置
     *
     * @param bufferedWriter 使用此实例方便清除 dest 内容或在 dest 中添加目录
     * @param dest           要操作的文件
     * @throws IOException 读取文件或写入失败抛出此异常
     */
    public abstract void insertToDirectory(BufferedWriter bufferedWriter, File dest) throws IOException;

    /**
     * 按怎么样的方式写入文件，由子类实现
     *
     * @throws IOException 详看{@link #mergeFile(File, File)}方法抛出的 {@code IOException} 说明
     */
    public abstract void operationMerge() throws IOException;

    /**
     * description: setDocumentContent <br>
     * version: 1.0 <br>
     * date: 2022/11/24 17:59 <br>
     * author: duanjiangcheng <br>
     * @param documentContent documentContent
     * @return void
     */
    public abstract void setDocumentContent(DocumentContent documentContent);
}
